package drds.server.sqlparser.parser;

import java.util.HashSet;
import java.util.List;

import drds.server.sqlparser.sqlobject.SqlObject;
import drds.server.sqlparser.sqlobject.expression.AggregateFunction;
import drds.server.sqlparser.sqlobject.expression.Between;
import drds.server.sqlparser.sqlobject.expression.BetweenWithPartitionKey;
import drds.server.sqlparser.sqlobject.expression.Expression;
import drds.server.sqlparser.sqlobject.expression.InList;
import drds.server.sqlparser.sqlobject.expression.InListWithpartitionKey;
import drds.server.sqlparser.sqlobject.expression.Variable;
import drds.server.sqlparser.sqlobject.expression.binary.BinaryExpression;
import drds.server.sqlparser.sqlobject.expression.binary.BinaryOperator;
import drds.server.sqlparser.sqlobject.expression.data_type.Null;
import drds.server.sqlparser.sqlobject.expression.data_type.Text;
import drds.server.sqlparser.sqlobject.expression.data_type.number.Decimal;
import drds.server.sqlparser.sqlobject.expression.data_type.number.Int;
import drds.server.sqlparser.sqlobject.expression.name.IName;
import drds.server.sqlparser.sqlobject.expression.name.Identifier;
import drds.server.sqlparser.sqlobject.expression.name.TableAliasName$ColumnName;

/**
 * 支持 union join 不支持 any some any exists。
 * 
 * @author 曹正辉<330937205@qq.com>
 * 
 */
public class ExpressionParser extends SqlParser {

	public final static HashSet<String> AGGREGATE_FUNCTION_NAME_SET = new HashSet<String>();
	static {
		// avg()=sum(nvl)/count(nvl)
		AGGREGATE_FUNCTION_NAME_SET.add("sum");
		AGGREGATE_FUNCTION_NAME_SET.add("count");
		AGGREGATE_FUNCTION_NAME_SET.add("avg");
		//
		AGGREGATE_FUNCTION_NAME_SET.add("max");
		AGGREGATE_FUNCTION_NAME_SET.add("min");
	}

	public ExpressionParser(String sql) {
		super(sql);
	}

	public ExpressionParser(Lexer lexer) {
		super(lexer);
	}

	public void accept(Mark mark) {
		if (lexer.getMark() == mark) {
		} else {
			throw new ParserException("syntax error, expect " + mark + ", actual " + lexer.getMark() + " " + lexer.stringValue());
		}
	}

	/**
	 * 值
	 */
	public Expression valueForUpdate() {

		final Mark mark = lexer.getMark();
		switch (mark) {
		/**
		 * 表达式
		 */
		case IDENTIFIER:
			Identifier left = new Identifier(lexer.stringValue());
			return parseAddOrSub(left);
			/**
			 * '字符串'
			 */
		case STRING:
			return new Text(lexer.stringValue());
			/**
			 * 整数
			 */
		case INT:
			return new Int(lexer.intValue());
			/**
			 * 小数
			 */
		case DECIMAL:
			return new Decimal(lexer.decimalValue());
			/**
			 * ?
			 */
		case VARIABLE: {
			Variable variable = new Variable("?");
			variable.setIndex(lexer.nextVariableIndex());
			return variable;
		}

		default:
			System.out.println("当前:" + lexer.mark);
			throw new IllegalArgumentException("else");

		}
	}

	/**
	 * 值
	 */
	public Expression value() {

		final Mark mark = lexer.getMark();
		switch (mark) {
		/**
		 * 表达式 针对join on语句会出现x.id=y.id的情况,单独提供一种解析方法
		 */
		case IDENTIFIER:
			return new Identifier(lexer.stringValue());
			/**
			 * '字符串'
			 */
		case STRING:
			return new Text(lexer.stringValue());
			/**
			 * 整数
			 */
		case INT:
			return new Int(lexer.intValue());
			/**
			 * 小数
			 */
		case DECIMAL:
			return new Decimal(lexer.decimalValue());
			/**
			 * ?
			 */
		case VARIABLE: {
			Variable variable = new Variable("?");
			variable.setIndex(lexer.nextVariableIndex());
			return variable;
		}

		default:
			System.out.println("当前:" + lexer.mark);
			throw new IllegalArgumentException("else");

		}
	}

	public final void parseListExpression(List<Expression> expressionList, SqlObject parent) {
		lexer.check(Mark.LEFT_PAREN);
		lexer.nextMark();
		// expression()最后必须nextMark...
		Expression expression = parseListExpression();
		expression.setParent(parent);
		expressionList.add(expression);

		while (lexer.getMark() == Mark.COMMA) {
			lexer.nextMark();
			expression = parseListExpression();
			expression.setParent(parent);
			expressionList.add(expression);
		}
		lexer.check(Mark.RIGHT_PAREN);
	}

	/**
	 * 解析列表-单元表达式(里面的元素可以为整数小数 字符串 ?)<br/>
	 * eg:insert table()values()<br/>
	 * ()
	 */
	private Expression parseListExpression() {
		Expression expression = null;

		final Mark mark = lexer.getMark();
		switch (mark) {
		/**
		 * 可能的实例为字段名,表别名.字段名
		 */
		case IDENTIFIER:
			expression = new Identifier(lexer.stringValue());
			lexer.nextMark();
			break;
		//
		/**
		 * '字符串'
		 */
		case STRING:
			expression = new Text(lexer.stringValue());
			lexer.nextMark();
			break;
		/**
		 * 整数
		 */
		case INT:
			expression = new Int(lexer.intValue());
			lexer.nextMark();
			break;
		/**
		 * 小数
		 */
		case DECIMAL:
			expression = new Decimal(lexer.decimalValue());
			lexer.nextMark();
			break;
		/**
		 * ?
		 * 
		 * <pre>
		 * 关于模糊查询like '%?%',一般不用于全库查询,如果要进行模糊查询,则需要进行带有切分键。
		 * </pre>
		 */
		case VARIABLE: {
			lexer.nextMark();
			Variable variable = new Variable("?");
			variable.setIndex(lexer.nextVariableIndex());
			expression = variable;
			break;
		}
		//
		case EOF:
			throw new EOF();
		default:
			throw new ParserException("ERROR. token : " + mark + ", pos : " + lexer.index());
		}
		return expression;
	}

	/**
	 * name的两种形式 a a.b<br/>
	 * 结尾的时候已经nextMark
	 */
	public IName parseName() {
		lexer.check(Mark.IDENTIFIER);
		String stringValue = lexer.stringValue();
		IName name = new Identifier(stringValue);
		lexer.nextMark();// 已经nextMark
		name = parseNameRest(name);
		System.out.println("当前where name=" + name.getName());
		return name;
	}

	public IName parseNameRest(IName name) {
		if (lexer.getMark() == Mark.DOT) {
			lexer.nextMark();
			lexer.check(Mark.IDENTIFIER);
			name = new TableAliasName$ColumnName(name, lexer.stringValue());
			lexer.nextMark();// 已经nextMark
		}

		return name;
	}

	/**
	 * <pre>
	 * ============================================================
	 * 更新字段相关的表达式
	 * ============================================================
	 * </pre>
	 */

	/**
	 * 加法和减法:a=a+b a=b+c。该操作只存在于更新语句。
	 */
	public Expression parseAddOrSub(Expression left) {
		// 表达式必须是a a.b
		if (left == null) {
			throw new NullPointerException(Expression.class.getSimpleName());
		}
		if (!(left instanceof Identifier)) {
			throw new IllegalArgumentException("not " + Identifier.class.getSimpleName());
		}
		// 之前必须是表示符
		// 针对标识符,该方法只处理之后的+-操作,其他相关操作在其他的方法里面进行。
		lexer.check(Mark.IDENTIFIER);
		lexer.nextMark();
		//
		if (lexer.getMark() == Mark.ADD) {// +
			lexer.nextMark();
			Expression right = value();

			return new BinaryExpression(left, BinaryOperator.Add, right);
		} else if (lexer.getMark() == Mark.SUB) { // -
			lexer.nextMark();
			Expression right = value();

			return new BinaryExpression(left, BinaryOperator.Subtract, right);
		} else {
			// throw new IllegalArgumentException("else...");
			return left;// 该处有个设计上的bug
		}
	}

	protected String parseAs() {
		String alias = null;
		if (lexer.getMark() == Mark.AS) {
			lexer.nextMark();
			lexer.check(Mark.IDENTIFIER);
			alias = lexer.stringValue();
			lexer.nextMark();
		}

		return alias;
	}

	/**
	 * <pre>
	 * ============================================================
	 * 解析关系表达式
	 * ============================================================
	 * </pre>
	 */
	/**
	 * 解析关系表达式。最小单元。
	 */
	public Expression parseRelationalExpression() {
		Expression expression = parseName();
		return parseRelationalExpressionRest(expression);
	}

	/**
	 * <pre>
	 * = !=右表达式只能是数字,?,字符串。
	 * > >= < <=右表达式只能是数字,? 不能是字符串。
	 * like right_like escape regexp 右表达式只能是字符串。
	 * is null is not null 
	 * between and 只能是字符串。 
	 * in (x,y,z)
	 * 
	 * </pre>
	 */
	public Expression parseRelationalExpressionRest(Expression left) {
		// 切分键
		if (lexer.getMark() == Mark.PARTITION_KEY_EQ) {
			lexer.nextMark();
			Expression right = value();
			return left = new BinaryExpression(left, BinaryOperator.PartitionKeyEq, right);
		} else if (lexer.getMark() == Mark.PARTITION_KEY_LESSTHAN) {
			BinaryOperator binaryOperator = BinaryOperator.PartitionKeyLessThan;
			lexer.nextMark();
			if (lexer.getMark() == Mark.Equal) {
				lexer.nextMark();
				binaryOperator = BinaryOperator.PartitionKeyLessThanOrEqual;
			}
			Expression right = value();
			return left = new BinaryExpression(left, binaryOperator, right);
		} else if (lexer.getMark() == Mark.PARTITION_KEY_GREATERTHAN) {
			BinaryOperator operator = BinaryOperator.PartitionKeyGreaterThan;
			lexer.nextMark();
			if (lexer.getMark() == Mark.Equal) {
				lexer.nextMark();
				operator = BinaryOperator.PartitionKeyGreaterThanOrEqual;
			}
			Expression right = value();
			return left = new BinaryExpression(left, operator, right);
		} else if (lexer.getMark() == (Mark.PARTITION_KEY_BETWEEN)) {
			lexer.nextMark();
			Expression begin = value();
			lexer.nextMark();
			accept(Mark.AND);
			lexer.nextMark();
			Expression end = value();
			return left = new BetweenWithPartitionKey(left, begin, end);
			/**
			 * 上面是BETWEEN AND
			 */
		} else if (lexer.getMark() == Mark.PARTITION_KEY_IN) {
			return left = parseInWithPartitionKey(left);
			/**
			 * 上面是in(x,y,z);
			 */
		} else //
				// 上面是针对切分键支持的算法
				//
		if (lexer.getMark() == Mark.Equal) {
			lexer.nextMark();
			Expression right = value();
			return left = new BinaryExpression(left, BinaryOperator.Equal, right);
		} else if (lexer.getMark() == Mark.NotEqual) {
			lexer.nextMark();
			Expression right = value();
			return left = new BinaryExpression(left, BinaryOperator.NotEqual, right);
		} else if (lexer.getMark() == Mark.LessThan) {
			BinaryOperator binaryOperator = BinaryOperator.LessThan;
			lexer.nextMark();
			if (lexer.getMark() == Mark.Equal) {
				lexer.nextMark();
				binaryOperator = BinaryOperator.LessThanOrEqual;
			}
			Expression right = value();
			return left = new BinaryExpression(left, binaryOperator, right);
		} else if (lexer.getMark() == Mark.LessThanOrEqual) {
			lexer.nextMark();
			Expression right = value();
			return left = new BinaryExpression(left, BinaryOperator.LessThanOrEqual, right);
		} else if (lexer.getMark() == Mark.GreaterThan) {
			BinaryOperator operator = BinaryOperator.GreaterThan;
			lexer.nextMark();
			if (lexer.getMark() == Mark.Equal) {
				lexer.nextMark();
				operator = BinaryOperator.GreaterThanOrEqual;
			}
			Expression right = value();
			return left = new BinaryExpression(left, operator, right);
		} else if (lexer.getMark() == Mark.GreaterThanOrEqual) {
			lexer.nextMark();
			Expression right = value();
			return left = new BinaryExpression(left, BinaryOperator.GreaterThanOrEqual, right);
			/**
			 * 上面是= != < <= > >=
			 */
		} else if (lexer.getMark() == Mark.LIKE) {
			lexer.nextMark();
			Expression right = value();

			return left = new BinaryExpression(left, BinaryOperator.Like, right);

		} else if (lexer.getMark() == Mark.IS) {
			lexer.nextMark();
			Null NULL = new Null();
			if (lexer.getMark() == Mark.NOT) {
				lexer.nextMark();
				lexer.check(Mark.NULL);
				return left = new BinaryExpression(left, BinaryOperator.IsNot, NULL);
			} else {
				lexer.check(Mark.NULL);
				return left = new BinaryExpression(left, BinaryOperator.Is, NULL);
			}
			/**
			 * 上面是IS NOT NULL IS NULL
			 */
		} else if (lexer.getMark() == (Mark.BETWEEN)) {
			lexer.nextMark();
			Expression begin = value();
			lexer.nextMark();
			accept(Mark.AND);
			lexer.nextMark();
			Expression end = value();
			return left = new Between(left, begin, end);
			/**
			 * 上面是BETWEEN AND
			 */
		} else if (lexer.getMark() == Mark.IN) {
			return left = parseIn(left);
			/**
			 * 上面是in(x,y,z);
			 */
		} else if (lexer.getMark() == (Mark.NOT)) {
			lexer.nextMark();
			return left = parseNotRelationalExpressionRest(left);
		} else {
			// {name}之后必须含有表达式
			throw new ParserException("TODO " + lexer.getMark());

		}

	}

	/**
	 * 解析not之后的SQL
	 */
	public Expression parseNotRelationalExpressionRest(Expression left) {
		if (lexer.getMark() == (Mark.LIKE)) {
			lexer.nextMark();
			Expression right = value();
			return left = new BinaryExpression(left, BinaryOperator.NotLike, right);

		} else if (lexer.getMark() == (Mark.BETWEEN)) {
			lexer.nextMark();
			Expression begin = value();
			lexer.nextMark();
			accept(Mark.AND);
			lexer.nextMark();
			Expression end = value();
			return left = new Between(left, true, begin, end);
			/**
			 * 上面是BETWEEN AND
			 */
		} else if (lexer.getMark() == Mark.IN) {
			left = parseIn(left);
			if (left instanceof InList) {
				InList inList = (InList) left;
				inList.setNot(true);
			} else {
				throw new RuntimeException("else...");
			}
			return left;
			/**
			 * 上面是in(x,y,z)
			 */
		} else {
			// not之后必须含有表达式
			throw new ParserException("TODO " + lexer.getMark());
		}
	}

	/**
	 * <pre>
	 * a in (x,y,z) or b in (select * from c) 尽可能支持 a b in (select a b from table)
	 * 如果是in,则有三种处理方式.如果是值(数字或者字符串),则根据其他条件进行查询。
	 * 如果是select语句,则需要根据条件进行查询:如果没有切分条件可以先在所有的数据库进行查询,或者按照切分条件进行查询。
	 * </pre>
	 */

	public final Expression parseInWithPartitionKey(Expression left) {
		if (lexer.getMark() == Mark.PARTITION_KEY_IN) {
			lexer.nextMark();

			InListWithpartitionKey inList = new InListWithpartitionKey(left);
			lexer.check(Mark.LEFT_PAREN);
			/**
			 * 可能是select 或者具体的数字或则字符串
			 */
			parseListExpression(inList.getItemList(), inList);
			accept(Mark.RIGHT_PAREN);
			if (inList.getItemList().size() == 0) {
				throw new IllegalArgumentException("非法SQL");
			}
		}

		return left;
	}

	public final Expression parseIn(Expression left) {
		if (lexer.getMark() == Mark.IN) {
			lexer.nextMark();

			InList inList = new InList(left);
			lexer.check(Mark.LEFT_PAREN);
			/**
			 * 可能是select 或者具体的数字或则字符串
			 */
			parseListExpression(inList.getItemList(), inList);
			accept(Mark.RIGHT_PAREN);
			if (inList.getItemList().size() == 0) {
				throw new IllegalArgumentException("非法SQL");
			}
		}

		return left;
	}

	/**
	 * <pre>
	 * ============================================================
	 * 条件相关的表达式
	 * ============================================================
	 * </pre>
	 */
	/**
	 * 针对update和delete语句客户端都必须带上 where 1=1 语句才能被提交到服务端。
	 */
	public Expression parseExpression() {// 这个是关系表达式where 1=1 ...的入口
		Expression expression = parseName();
		return parseExpressionRest(expression);
	}

	public Expression parseExpressionRest(Expression expression) {
		/**
		 * 基本关系表达式
		 */
		expression = parseRelationalExpressionRest(expression);
		if (lexer.mark == Mark.RIGHT_PAREN) {// )终止
			return expression;
		}
		lexer.nextMark();
		/**
		 * and 优于 or
		 */
		expression = parseAndRest(expression);// 完整表达式
		if (lexer.mark == Mark.RIGHT_PAREN) {// )终止
			return expression;
		}
		lexer.nextMark();
		expression = parseOr(expression);// 完整表达式

		return expression;
	}

	public Expression parseAnd() {
		Expression expression = parseRelationalExpression();
		return parseAndRest(expression);
	}

	/**
	 * and处理
	 */
	public Expression parseAndRest(Expression left) {
		for (;;) {
			if (lexer.getMark() == Mark.AND) {
				lexer.nextMark();
				Expression right = parseRelationalExpression();
				left = new BinaryExpression(left, BinaryOperator.And, right);
				lexer.nextMark();// 得到下一个完整表达式
			} else {
				break;
			}
		}

		return left;
	}

	/**
	 * or处理
	 */
	public Expression parseOr(Expression left) {

		for (;;) {
			if (lexer.getMark() == Mark.OR) {
				lexer.nextMark();
				Expression right = parseAnd();
				left = new BinaryExpression(left, BinaryOperator.Or, right);
				lexer.nextMark();// 得到下一组表达式
			} else {
				break;
			}
		}

		return left;
	}

	/**
	 * 解析method之后
	 */
	protected Expression parseMethodRest(Expression expression) {
		accept(Mark.LEFT_PAREN);
		if (expression instanceof IName) {
			String methodName = expression.toString();
			if (isAggreateFunction(methodName)) {
				AggregateFunction aggregateFunction = parseAggregateFunction(methodName);
				accept(Mark.RIGHT_PAREN);
				return aggregateFunction;
			} else {
				throw new RuntimeException("不支持其他的函数");
			}

		} else {
			throw new ParserException("not support token:" + lexer.getMark());
		}

	}

	public boolean isAggreateFunction(String methodName) {
		return AGGREGATE_FUNCTION_NAME_SET.contains(methodName);
	}

	protected AggregateFunction parseAggregateFunction(String methodName) {
		AggregateFunction aggregateFunction = new AggregateFunction(methodName);
		lexer.nextMark();
		parseListExpression(aggregateFunction.getArgumentList(), aggregateFunction);

		accept(Mark.RIGHT_PAREN);

		return aggregateFunction;
	}

}
